package com.github.caiqy.shirodemo.core;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.ibatis.exceptions.TooManyResultsException;
import org.springframework.beans.factory.annotation.Autowired;
import tk.mybatis.mapper.entity.Condition;
import tk.mybatis.mapper.entity.Example;

import java.lang.reflect.ParameterizedType;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

/**
 * 基于通用MyBatis Mapper插件的Service接口的实现 2019/4/18 11:28
 */
public abstract class AbstractService<T> implements Service<T> {

    @Autowired
    protected Mapper<T> mapper;

    /**
     * 当前泛型真实类型的Class
     */
    private Class<T> modelClass;

    @SuppressWarnings("unchecked")
    public AbstractService() {
        ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass();
        modelClass = (Class<T>) pt.getActualTypeArguments()[0];
    }

    @Override
    public Integer insert(T model) {
        return mapper.insertSelective(model);
    }

    @Override
    public Integer insertList(List<T> models) {
        return mapper.insertList(models);
    }

    @Override
    public Integer deleteById(Object id) {
        return mapper.deleteByPrimaryKey(id);
    }

    @Override
    public Integer deleteBy(String property, Object value) {
        Example example = new Example(modelClass);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo(property, value);
        example.and(criteria);
        return mapper.deleteByExample(example);
    }

    @Override
    public Integer deleteByIds(String ids) {
        return mapper.deleteByIds(ids);
    }

    @Override
    public Integer deleteByIds(Iterable ids) {
        return mapper.deleteByIds(CommonUtils.join(ids, ','));
    }

    @Override
    public Integer update(T model) {
        return mapper.updateByPrimaryKeySelective(model);
    }

    @Override
    public Integer updateByExampleSelective(T record, Example example) {
        return mapper.updateByExampleSelective(record, example);
    }

    @Override
    public T selectById(Object id) {
        return mapper.selectByPrimaryKey(id);
    }

    @Override
    public T selectBy(String fieldName, Object value) throws TooManyResultsException {
        Example example = new Example(modelClass);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo(fieldName, value);
        example.and(criteria);
        return mapper.selectOneByExample(example);
    }

    @Override
    public List<T> selectListBy(String fieldName, Object value) {
        Example example = new Example(modelClass);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo(fieldName, value);
        return mapper.selectByExample(example);
    }

    @Override
    public List<T> selectListIn(String fieldName, Collection<?> collection) {
        if (CommonUtils.isEmpty(collection)) {
            return mapper.selectAll();
        } else {
            Example example = new Example(modelClass);
            Example.Criteria criteria = example.createCriteria();
            criteria.andIn(fieldName, collection);
            return mapper.selectByExample(example);
        }
    }

    @Override
    public List<T> selectListBy(FieldValue... fvs) {
        if (fvs != null && fvs.length > 0) {
            Example example = new Example(modelClass);
            Example.Criteria criteria = example.createCriteria();
            for (FieldValue fv : fvs) {
                criteria.andEqualTo(fv.getField(), fv.getValue());
            }
            return mapper.selectByExample(example);
        }
        return mapper.selectAll();
    }

    @Override
    public List<T> selectAscDescListBy(String fieldName, Object value, List<String> ascProperties, List<String> descProperties) {
        Example example = new Example(modelClass);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo(fieldName, value);

        if (!isEmpty(ascProperties)) {
            for (String ascProperty : ascProperties) {
                example.orderBy(ascProperty).asc();
            }
        }

        if (!isEmpty(descProperties)) {
            for (String descProperty : descProperties) {
                example.orderBy(descProperty).desc();
            }
        }

        return mapper.selectByExample(example);
    }

    @Override
    public List<T> selectDescAscListBy(String fieldName, Object value, List<String> ascProperties, List<String> descProperties) {
        Example example = new Example(modelClass);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo(fieldName, value);

        if (!isEmpty(descProperties)) {
            for (String descProperty : descProperties) {
                example.orderBy(descProperty).desc();
            }
        }

        if (!isEmpty(ascProperties)) {
            for (String ascProperty : ascProperties) {
                example.orderBy(ascProperty).asc();
            }
        }

        return mapper.selectByExample(example);
    }

    @Override
    public List<T> selectAscListBy(String fieldName, Object value, String... properties) {
        return selectAscDescListBy(fieldName, value, Arrays.asList(properties), null);
    }

    @Override
    public List<T> selectDescListBy(String fieldName, Object value, String... properties) {
        return selectDescAscListBy(fieldName, value, null, Arrays.asList(properties));
    }

    @Override
    public int countBy(String fieldName, Object value) {
        Example example = new Example(modelClass);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo(fieldName, value);
        example.and(criteria);
        return mapper.selectCountByExample(example);
    }

    @Override
    public List<T> selectListByIds(String ids) {
        return mapper.selectByIds(ids);
    }

    @Override
    public List<T> selectListByIds(Iterable ids) {
        return mapper.selectByIds(CommonUtils.join(ids, ','));
    }

    @Override
    public List<T> selectByCondition(Condition condition) {
        return mapper.selectByCondition(condition);
    }

    @Override
    public List<T> selectAll() {
        return mapper.selectAll();
    }

    @Override
    public List<T> select(T record) {
        return mapper.select(record);
    }

    @Override
    public T selectOne(T record) {
        return mapper.selectOne(record);
    }

    @Override
    public List<T> selectByCondition(Condition condition, int pageIndex, int pageSize) {
        PageHelper.startPage(pageIndex, pageSize);
        return mapper.selectByCondition(condition);
    }

    @Override
    public List<T> selectByExample(Example example) {
        return mapper.selectByExample(example);
    }

    @Override
    public List<T> selectByExample(Example example, int pageIndex, int pageSize) {
        PageHelper.startPage(pageIndex, pageSize);
        return mapper.selectByExample(example);
    }

    @Override
    public PageInfo<T> selectAll(int pageIndex, int pageSize) {
        PageHelper.startPage(pageIndex, pageSize);
        List<T> list = mapper.selectAll();
        return new PageInfo<>(list);
    }

    @Override
    public PageInfo<T> select(T record, int pageIndex, int pageSize) {
        PageHelper.startPage(pageIndex, pageSize);
        List<T> list = mapper.select(record);
        return new PageInfo<>(list);
    }

    public boolean isEmpty(Collection<?> collection) {
        return collection == null || collection.isEmpty();
    }
}
